package com.yegs.hospital.service.impl;

import com.yegs.hospital.bo.TaskRequest;
import com.yegs.hospital.common.PageVo;
import com.yegs.hospital.dao.TaskDao;
import com.yegs.hospital.service.TaskService;
import com.yegs.hospital.util.ConfigConstant;
import com.yegs.hospital.vo.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentSkipListMap;

@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskDao taskDao;

    @Override
    public void save(Task task) {
        LocalDateTime start = task.getStartTime();
        LocalDateTime end = task.getEndTime();
        task.setUseTime(Duration.between(start, end).getSeconds() / 60);
        taskDao.save(task);
    }

    @Override
    public PageImpl<Task> list(TaskRequest pageParam) {
        Sort sort = Sort.by(Sort.Direction.DESC,"id");
        PageRequest request = PageRequest.of(pageParam.getPageNumber() - 1, pageParam.getPageSize(),sort);
        return (PageImpl<Task>) taskDao.findAll(TaskSpecs.getStudentByFilter(pageParam),request);
    }

    @Override
    public Task get() {
        return taskDao.findTaskByStatusEquals(ConfigConstant.STA_TASK_1);
    }

    @Override
    public Task get(String openId) {
        Task task = taskDao.findTaskByStatusEqualsAndOpenIdEquals(ConfigConstant.STA_TASK_1, openId);
        if(task == null){return task;}
        LocalDateTime start = task.getStartTime();
        LocalDateTime end = LocalDateTime.now();
        task.setEndTime(end);
        task.setUseTime(Duration.between(start, end).getSeconds() / 60);
        return task;
    }

    @Override
    public Task getLast(String openId) {
        Task task = taskDao.findFirstByOpenIdOrderByIdDesc(openId);
        if(task == null){return task;}
        LocalDateTime start = task.getStartTime();
        LocalDateTime end = task.getEndTime() == null ? LocalDateTime.now() : task.getEndTime();
        task.setUseTime(Duration.between(start, end).getSeconds() / 60);
        return task;
    }

    @Override
    public Task getEnd(String openId) {
        Task task = taskDao.findFirstByOpenIdOrderByIdDesc(openId);
        if(task == null){return task;}
        LocalDateTime start = task.getEndTime();
        LocalDateTime end = LocalDateTime.now();
        task.setUseTime(Duration.between(start, end).getSeconds() / 60);
        return task;
    }


    @Override
    public List<Task> findAll(String openId) {
        return taskDao.findTasksByOpenIdOrderByIdDesc(openId);
    }

    @Override
    public List<Task> findOutTime(String department) {
        return taskDao.findAll(OutTime1.get(department));
    }

    @Override
    public void finishTask(Long id) throws Exception {
        Task task = taskDao.getOne(id);
        if(task != null){
            task.setStatus(ConfigConstant.STA_TASK_2);
            LocalDateTime start = task.getStartTime();
            LocalDateTime end = LocalDateTime.now();
            task.setEndTime(end);
            task.setUseTime(Duration.between(start, end).getSeconds() / 60);
            taskDao.save(task);
            return;
        }
        throw new Exception("结束失败，错误ID！");
    }

    @Override
    public void delete(Long id) {
        taskDao.deleteById(id);
    }


    public static class TaskSpecs {
        //方法1。Specification：规格，规范。Predicate：断言。将复杂的查询提取成一个方法。
        public static Specification<Task> getStudentByFilter(TaskRequest filter){
            return new Specification<Task>() {//使用 Specification 的匿名内部类
                @Override
                /**
                 * @param *root: 代表查询的实体类.
                 * @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类.
                 * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂
                 * @return: *Predicate 类型, 代表一个查询条件.
                 */
                public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    List<Predicate> predicates  = new ArrayList<Predicate>();//将多个查询条件放在一个list中
                    if(filter.getEntity().getUsername() != null && !"".equals(filter.getEntity().getUsername())){
                        predicates.add(criteriaBuilder.like(root.<String>get("username"), "%" + filter.getEntity().getUsername() + "%"));
                    }
                    if(filter.getEntity().getStatus()!= null && !"".equals(filter.getEntity().getStatus())){
                        predicates.add(criteriaBuilder.equal(root.<String>get("status"), filter.getEntity().getStatus()));
                    }
                    if(filter.getLeftCreateTime()!= null && !"".equals(filter.getLeftCreateTime())){
                        predicates.add(criteriaBuilder.greaterThan(root.<LocalDateTime>get("createTime"), filter.getLeftCreateTime()));
                    }
                    if(filter.getRightCreateTime()!= null && !"".equals(filter.getRightCreateTime())){
                        predicates.add(criteriaBuilder.lessThanOrEqualTo(root.<LocalDateTime>get("createTime"), filter.getRightCreateTime()));
                    }
                    if(filter.getDepartment()!= null && !"".equals(filter.getDepartment())){
                        predicates.add(criteriaBuilder.equal(root.<LocalDateTime>get("department"), filter.getDepartment()));
                    }
                    //criteriaBuilder.and()返回一个predicate对象
                    return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
                }
            };
        }
        //还可以继续添加方法2
    }

    public static class OutTime {
        //方法1。Specification：规格，规范。Predicate：断言。将复杂的查询提取成一个方法。
        public static Specification<Task> get(){
            return new Specification<Task>() {//使用 Specification 的匿名内部类
                @Override
                /**
                 * @param *root: 代表查询的实体类.
                 * @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类.
                 * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂
                 * @return: *Predicate 类型, 代表一个查询条件.
                 */
                public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    List<Predicate> predicates  = new ArrayList<Predicate>();//将多个查询条件放在一个list中
//                    predicates.add(criteriaBuilder.greaterThan(root.<LocalDateTime>get("createTime"), LocalDateTime.now().plusMinutes(-30)));
//                    predicates.add(criteriaBuilder.equal(root.<String>get("type"), "探视"));
//                    predicates.add(criteriaBuilder.equal(root.<String>get("status"), "执行中"));
                    predicates.add(criteriaBuilder.lessThanOrEqualTo(root.<LocalDateTime>get("createTime"), LocalDateTime.now().plusMinutes(-3)));
                    predicates.add(criteriaBuilder.equal(root.<String>get("type"), ConfigConstant.STA_TYPE_0));
                    predicates.add(criteriaBuilder.equal(root.<String>get("status"), ConfigConstant.STA_TASK_1));
                    //criteriaBuilder.and()返回一个predicate对象
                    return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
                }
            }.or(
                new Specification<Task>() {//使用 Specification 的匿名内部类
                    @Override
                    /**
                     * @param *root: 代表查询的实体类.
                     * @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类.
                     * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂
                     * @return: *Predicate 类型, 代表一个查询条件.
                     */
                    public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                        List<Predicate> predicates  = new ArrayList<Predicate>();//将多个查询条件放在一个list中
//                        predicates.add(criteriaBuilder.greaterThan(root.<LocalDateTime>get("createTime"), LocalDateTime.now().plusMinutes(-150)));
//                        predicates.add(criteriaBuilder.equal(root.<String>get("type"), "看护"));
//                        predicates.add(criteriaBuilder.equal(root.<String>get("status"), "执行中"));
                        LocalDateTime.now().plusMinutes(-5);
                        predicates.add(criteriaBuilder.lessThanOrEqualTo(root.<LocalDateTime>get("createTime"), LocalDateTime.now().plusMinutes(-5)));
                        predicates.add(criteriaBuilder.equal(root.<String>get("type"), ConfigConstant.STA_TYPE_1));
                        predicates.add(criteriaBuilder.equal(root.<String>get("status"), ConfigConstant.STA_TASK_1));

                        //criteriaBuilder.and()返回一个predicate对象
                        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
                    }
                }
            );
        }
        //还可以继续添加方法2
    }

    public static class OutTime1 {
        //方法1。Specification：规格，规范。Predicate：断言。将复杂的查询提取成一个方法。
        public static Specification<Task> get(String department){
            return new Specification<Task>() {//使用 Specification 的匿名内部类
                @Override
                public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    List<Predicate> predicates  = new ArrayList<Predicate>();//将多个查询条件放在一个list中
                    predicates.add(criteriaBuilder.lessThanOrEqualTo(root.<LocalDateTime>get("createTime"), LocalDateTime.now().plusMinutes(-30)));
                    predicates.add(criteriaBuilder.equal(root.<String>get("type"), "探视"));
                    predicates.add(criteriaBuilder.equal(root.<String>get("status"), "执行中"));
                    if(department!= null && !"".equals(department) && !"null".equals(department)){
                        predicates.add(criteriaBuilder.equal(root.<String>get("department"), department));
                    }
                    //criteriaBuilder.and()返回一个predicate对象
                    return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
                }
            };
        }
    }
    
}
